ITERATION AND CONDITIONAL MENU:
copyright (C) 1983 by E. E. Bergmann
iteration
BEGIN ... END
BEGIN .. IF ... END
DO LOOPs
IF ... THEN and IF ... ELSE ... THEN
"case" construction
"recursion"
:
::
*********************************************************
*							*
* PISTOL-Portably Implemented Stack Oriented Language   *
*			Version 2.0			*
* (C) 1983 by	Ernest E. Bergmann			*
*		Physics, Building #16			*
*		Lehigh Univerisity			*
*		Bethlehem, Pa. 18015			*
*							*
* Permission is hereby granted for all reproduction and *
* distribution of this material provided this notice is *
* included.						*
*							*
*********************************************************
:
::
	PISTOL provides four means for iterative execution
of a sequence of words, namely:

BEGIN ... END

	executes words between BEGIN and END until a
condition is satisfied.

BEGIN ... IF ... REPEAT

	is similar to BEGIN ... END except the condition is
tested at the beginning of the loop; iteration terminates
when the tested condition is false.

DO ... LOOP

	executes the words between DO and LOOP, running an
index [accessible as "I"] from a lower to upper limit,
incrementing by one each time.

DO ... n +LOOP

	executes the words between DO and +LOOP, running
an index from a lower to an upper limit, incrementing 
by n each time.

	Iterations may be nested subject to the normal
restrictions on overlapping ranges, i.e. any iteration which
is initiated within the range of another iteration must be
terminated within that same range.  PISTOL has implemented a
"check stack" to enforce this syntax rule and, as an aid to
interactive programming, displays this stack in the prompt.

:
::
BEGIN ... END
=============
	The BEGIN ... END syntax permits the user to execute
a sequence of words and then, depending upon a computed
logical variable, either loop back or continue on:

BEGIN word1 word2 .... wordm END

	The sequence word1, word2, ... is executed once.
When END is reached, the top of the stack is popped and
tested.  If it is true (non-zero) then control passes to the
word following END.  If it is false (zero) then control
passes back to the word following BEGIN.

An example:

	'EXAMPLE : BEGIN 1- DUP DUP = EQZ END DROP ;

	defines the word EXAMPLE which might be called
	as follows:

	X>  5 EXAMPLE
	4 3 2 1 0

	Each time through the loop, the top of the stack
	(initially the number 5) is decremented, printed and
	compared to zero.  If it is not zero, the loop is
	repeated; the loop terminates when it becomes zero.

:
::
BEGIN ... IF ... REPEAT
=======================
	BEGIN ... IF ... REPEAT is similar to BEGIN ... END
except that the test is at the beginning of the loop.  The
words between BEGIN and IF are executed. The top of the
stack is then popped and tested.  If it is true (non-zero)
the words between IF and REPEAT are executed and control
passes back to the first word after BEGIN. If the top of the
stack had been tested false (zero) control would have passed
to the word following REPEAT.

An example:

	'LENGTH : 0 BEGIN SWAP DUP IF W@ SWAP 1+ REPEAT UNDER ;

	might be used to determine the length of a chain of
	pointers terminated by zero.  The initial pointer
	would be placed on the stack and LENGTH would be
	invoked.  If one could not place the test at the
	beginning of the iteration, one would have a problem
	with a zero length chain (a zero initially on the
	 stack).


:
::
DO LOOPS
========
	A DO LOOP facility is provided by PISTOL for indexing
through a sequence of words.  There are two forms of DO LOOP:

HIGH LOW DO word1 word2 ... wordn LOOP

HIGH LOW DO word1 word2 ... wordn STEP +LOOP

	The limits HIGH and LOW (the top two stack entries) are
compared.  If HIGH is less than or equal to LOW, control passes
to the word following LOOP or +LOOP.  Otherwise, the sequence
word1, word2, ... is executed.  LOOP causes the lower limit,
LOW to be incremented and compared to the upper limit, HIGH.
If LOW is greater than or equal to HIGH, the loop is
terminated.  Otherwise another iteration is performed. The
+LOOP is identical to LOOP except that the LOW is incremented
by the word on top of stack, STEP. Normally, STEP would be a
positive number.

	Within the range of a loop, the current value of the
loop index is available by using "I".  If DO LOOPs are nested,
I contains always the value of the innermost index.  The next
outer indices are available using the words, J and K.  The word
I' is used to obtain the value of (HIGH+LOW-I-1).  This is used
to run an index backwards from HIGH-1 to LOW .  The words J'
and K' are similarly defined.  When parenthesis (iteration
brackets) are nested with DO LOOPs, they count as one level of
indexing.  When I is used within the range of an iteration
bracket the current iteration count (which runs from its
initial value downwards to one) is placed on stack.

	The word EXIT causes the innermost loop in which
it is embedded to terminate unconditionally.

Some examples:

	5 0 DO I = LOOP

	causes the numbers 0 to 4, inclusive to be typed out.

	5 0 DO 5 0 DO J 5 * I + = LOOP CR LOOP

	causes the numbers 0 through 24 inclusive to be
	typed out as 5 lines of 5 numbers each.

	5 0 DO I' = LOOP

	causes the numbers 4 ... 0, inclusive to be output.

	0 21 1 DO I + DUP = 2 +LOOP DROP

	types out the first 10 perfect squares starting with 1.

	When using I' (or J' or K') in conjunction with +LOOP,
HIGH should be replaced by HIGH - STEP + 1  if it is desired
to produce the same set of indices as with I .  For example:

	X>  24 0  DO I = 4 +LOOP
	0 4 8 12 16 20

	X>  24 0 DO I' = 4 +LOOP
	23 19 15 11 7 3 1

	X>  24 4 - 1+ 0 DO I' = 4 +LOOP
	20 16 12 8 4 0

:
::
CONDITIONALS
============

	PISTOL has a powerful IF ... ELSE ... THEN construction
which allows moderately complex logical tests to be performed.
In addition, for more complex situations an OFCASE ... ENDCASE
n-branch construction is provided also [the"CASE"construction].
Conditionals may be nested within each other and within
iteration loops with the same restrictions that apply to
iterations.  The check stack enforces that proper nesting is
maintained and will issue fatal error messages otherwise.  The
prompt provides the user with information on the current
nesting status.

	For purposes of the conditional, "true" is considered
to be any non-zero value; "false" is any zero value. [The
"best" true value is -1, viz. all 1's in binary, in that
"-1 N AND" will be always "true" unless N is "false".]

val IF true1 true2 ... ELSE false1 false2 ... THEN

	The top of stack, val is tested and

	if true (non-zero), the words true1,true2,...
	are executed; control passes then to the word
	following THEN,

	otherwise, if false (zero) control passes to false1 ,
	false2 ... ; control passes then to the word
	following THEN, 

Two examples:

	'ABS : DUP LTZ IF MINUS THEN ;

	defines the word ABS which replaces the top of stack
	with its absolute value.

	'MAX : DDUP GT IF DROP ELSE UNDER THEN ;

	defines the word MAX which compares the top two stack
	entries and leaves the larger of the two.

:
::
	The CASE construction simplifies many programs where
the value of a variable is used to choose among many
possibilities. Its syntax is necessarily more complex:

value	OFCASE	<test1> C: <action1> ;C
		<test2> C: <action2> ;C
		.	.	.	.
		.	.	.	.
		<testn> C: <actionn> ;C
	ENDCASE

	The liberal use of carriage returns and tabs in the
coding improves readability, but is not required by the syntax.
OFCASE saves value and replaces it on the stack before each
test. If <test1> is true then <action1> (which may be any
number of words) is carried out and control skips to the first
word after ENDCASE. Otherwise, if <test1> is false, value is
again placed on stack and <test2> performed;  if it proves true
then <action2> is done and control passes to the word following
ENDCASE, etc. Thus the first successful test selects the action
performed.

	If every test, including <testn> is false, control
reaches ENDCASE and a fatal error message is generated.
An example should clarify this (notice how the prompt changes):

X> 'SPELL : OFCASE
X:C> 0 EQ C: 'ZERO ;C
X:C> 1 EQ C: 'ONE ;C
X:C> 2 EQ C: 'TWO ;C
X:C> 2 GT C: 'MANY ;C
X:C> ENDCASE MSG ;

When testing this definition one finds:

X> 2 SPELL
TWO
X> 3 SPELL
MANY
X> -1 SPELL
CASE EXECUTION ERROR AT 11672 FOR THE VALUE -1       PISTOL

	The fatal error message provides the address of ENDCASE
and the value that created the problem.

	OFCASE does not use the loop stack but uses its own
"CASE" stack;  the words I , J , K , I' , J' , K' and EXIT will
properly access the DO...LOOP counters when intermixed with
this structure. The words, ICASE and JCASE, access the case
variable of the innermost OFCASE structure and the next to
innermost OFCASE structure, respectively.  They are somewhat
analogous to the words I and J of the DO LOOP structure.

:
::
RECURSION
=========
	Normally, a procedure cannot invoke itself because it
is compiled before its own name is recorded;  therefore the
word RECURSE is provided as a "stand-in" for the name of the
procedure being defined.  This word also provides the means for
recursing within the compile buffer, itself.  For example,
one might wish to define FACTORIAL by:

'FACTORIAL : DUP 1 EQ LNOT IF
		DUP 1 - FACTORIAL * THEN
	   ;

However, FACTORIAL is not yet defined until this current
definition has been compiled.  We should use the word,
RECURSE, instead:

'FACTORIAL : DUP 1 EQ LNOT IF
		DUP 1 - RECURSE * THEN
	   ;

	It is possible to use RECURSE for directly executing
code from the compile buffer as well:

X> 3
1X> DUP 1 EQ LNOT IF DUP 1 - RECURSE * THEN
1X> =
6

	For recursion which requires forward references one
has to make an extra effort (as one does in PASCAL, which
requires the use of the reserved word, FORWARD). In PISTOL
we must define first a variable, say, FORW, which is
destined to contain the address of the forward reference.
One defines then those routines that invoke the
forward-referenced routine with the code:

	... FORW W@ EXEC ...

Eventually, one is in the position to define the routine that
is needed to complete the recursive circle, say, LAST.  After
defining LAST the recursive loop is established with:

	'LAST ADDRESS FORW W!

which records the address of LAST in the variable, FORW .

:
